﻿using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using ParserGenerator.GrammarConstruction;

namespace ParserGenerator.ParserConstruction
{
    [Serializable]
    public sealed class ParserAutomatonTransitions : ReadOnlyDictionary<GrammarSymbol, ParserAutomatonTransition>
    {
        public ParserAutomatonState State { get; }

        internal ParserAutomatonTransitions(ParserAutomatonState state)
            : base(new Dictionary<GrammarSymbol, ParserAutomatonTransition>())
        {
            if (state == null)
                throw new ArgumentNullException(nameof(state));
            State = state;
        }

        internal ParserAutomatonTransitions(ParserAutomatonState state, ParserAutomatonTransitions other)
            : base(new Dictionary<GrammarSymbol, ParserAutomatonTransition>(other))
        {
            if (state == null)
                throw new ArgumentNullException(nameof(state));
            State = state;
        }

        internal void Add(GrammarSymbol symbol, ParserAutomatonState target)
        {
            if (symbol == null)
                throw new ArgumentNullException(nameof(symbol));
            if (target == null)
                throw new ArgumentNullException(nameof(target));
            ParserAutomatonTransition tran = new ParserAutomatonTransition(State, symbol, target);
            Dictionary.Add(symbol, tran);
        }

        internal void Update(GrammarSymbol symbol, ParserAutomatonState target)
        {
            if (symbol == null)
                throw new ArgumentNullException(nameof(symbol));
            if (target == null)
                throw new ArgumentNullException(nameof(target));
            ParserAutomatonTransition tran = new ParserAutomatonTransition(State, symbol, target);
            Dictionary[symbol] = tran;
        }

        public ParserAutomatonTransition GetTransition(GrammarSymbol symbol)
        {
            if (symbol == null)
                throw new ArgumentNullException(nameof(symbol));
            ParserAutomatonTransition tran;
            if (!Dictionary.TryGetValue(symbol, out tran))
            {
                string message = string.Format(SR.NoTransitionDefinedForStateAndSymbol, State, symbol);
                InvalidOperationException e = new InvalidOperationException(message);
                throw e;
            }
            return tran;
        }

        public new ParserAutomatonState this[GrammarSymbol symbol]
        {
            get
            {
                if (symbol == null)
                    throw new ArgumentNullException(nameof(symbol));
                ParserAutomatonTransition tran = GetTransition(symbol);
                return tran.Target;
            }
        }
    }
}
